﻿
using System;
using System.Collections.Generic;
using CatEars.Core.Collections;

namespace CatEars.Core.Numbers
{
    /// <summary>
    /// 单位转换(统一使用double类型，但是超大数字可能会损失精度)
    /// </summary>
    public partial class UnitConv
    {
        #region 静态方法
        /// <summary>
        /// 单位转换
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="fromIndex">输入单位在转换索引中的位置</param>
        /// <param name="toIndex">输出单位在转换索引中的位置</param>
        /// <param name="convArr">转换索引数组 以“毫秒 秒 分 度”为例convArr为“1000, 60, 60, 60”</param>
        /// <returns>转换后的值</returns>
        public static double Convert(double value, int fromIndex, int toIndex, double[] convArr)
        {
            double power = 1;
            if (fromIndex == toIndex)
            {
                return value;
            }
            else if (fromIndex > toIndex)
            {
                for (int i = toIndex; i < fromIndex; ++i)
                {
                    power *= convArr[i];
                }
                return value * power;
            }
            else
            {
                for (int i = fromIndex; i < toIndex; ++i)
                {
                    power *= convArr[i];
                }
                return value / power;
            }
        }
        /// <summary>
        /// 单位转换(代码同double版的)
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="fromIndex">输入单位在转换索引中的位置</param>
        /// <param name="toIndex">输出单位在转换索引中的位置</param>
        /// <param name="convArr">转换索引数组 以“毫秒 秒 分 度”为例convArr为“1000, 60, 60, 60”</param>
        /// <returns>转换后的值</returns>
        public static int Convert(int value, int fromIndex, int toIndex, int[] convArr)
        {
            int power = 1;
            if (fromIndex == toIndex)
            {
                return value;
            }
            else if (fromIndex > toIndex)
            {
                for (int i = toIndex; i < fromIndex; ++i)
                {
                    power *= convArr[i];
                }
                return value * power;
            }
            else
            {
                for (int i = fromIndex; i < toIndex; ++i)
                {
                    power *= convArr[i];
                }
                return value / power;
            }
        }
        /// <summary>
        /// 单位转换(代码同double版的)
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="fromIndex">输入单位在转换索引中的位置</param>
        /// <param name="toIndex">输出单位在转换索引中的位置</param>
        /// <param name="convArr">转换索引数组 以“毫秒 秒 分 度”为例convArr为“1000, 60, 60, 60”</param>
        /// <returns>转换后的值</returns>
        public static long Convert(long value, int fromIndex, int toIndex, long[] convArr)
        {
            long power = 1;
            if (fromIndex == toIndex)
            {
                return value;
            }
            else if (fromIndex > toIndex)
            {
                for (int i = toIndex; i < fromIndex; ++i)
                {
                    power *= convArr[i];
                }
                return value * power;
            }
            else
            {
                for (int i = fromIndex; i < toIndex; ++i)
                {
                    power *= convArr[i];
                }
                return value / power;
            }
        }
        #endregion

        /// <summary>
        /// 初始化单位转换器
        /// </summary>
        /// <param name="powerArr">示例“1000, 60, 60” 长度为3</param>
        /// <param name="nameArr">示例“毫秒 秒 分 度” 长度为4</param>
        public UnitConv(double[] powerArr, string[] nameArr)
        {
            if (powerArr == null || powerArr.Length == 0)
            {
                throw new ArgumentNullException("powerArr", "powerArr必须有内容");
            }
            PowerArr = powerArr;
            if (nameArr != null)
            {
                NameArr = nameArr;
                if (nameArr.Length <= powerArr.Length)
                {
                    throw new ArgumentNullException("nameArr", "nameArr长度至少要比powerArr大1");
                }
                for (int i = 0; i < nameArr.Length; i++)
                {
                    NameDict.Add(nameArr[i], i);
                }
            }
            else
            {
                nameArr = EmptyArray.StringArray;
            }
        }

        /// <summary>
        /// 转换数组
        /// </summary>
        public double[] PowerArr { get; private set; }

        /// <summary>
        /// 单位名称数组
        /// </summary>
        public string[] NameArr { get; private set; }

        /// <summary>
        /// 单位名称索引字典
        /// </summary>
        protected Dictionary<string, int> NameDict
            = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// 获取单位所用的进制转换值在PowerArr中的位置
        /// </summary>
        /// <param name="strUnit">单位名称</param>
        /// <returns>进制转换值在PowerArr中的位置</returns>
        public int GetUnitIndex(string strUnit)
        {
            int intResult;
            if (!NameDict.TryGetValue(strUnit, out intResult))
            {
                intResult = -1;
            }
            return intResult;
        }

        /// <summary>
        /// 进行转换
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <param name="strFromName">当前单位</param>
        /// <param name="strToName">转换后单位</param>
        /// <returns>转换后的值</returns>
        public double Convert(double value, string strFromName, string strToName)
        {
            int intFromIndex = GetUnitIndex(strFromName);
            int intToIndex = GetUnitIndex(strToName);
            return UnitConv.Convert(value, intFromIndex, intToIndex, PowerArr);
        }

        /// <summary>
        /// 进行转换
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <param name="intFromIndex">当前单位进制转换值在PowerArr中的位置</param>
        /// <param name="intToIndex">转换后单位进制转换值在PowerArr中的位置</param>
        /// <returns>转换后的值</returns>
        public double Convert(double value, int intFromIndex, int intToIndex)
        {
            return UnitConv.Convert(value, intFromIndex, intToIndex, PowerArr);
        }
    }
}
